﻿//===================================================================================
// Copyright (c) Ryan Garrett.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===================================================================================

//WRITE: Unless the field is protected, this attribute will not be found
using System;

namespace Caffeine.Core
{
    /// <summary>
    /// Allows you to mark a field as a backing field for a ModelProperty. This type is meant
    /// to be used by the code generated from CMF snippets.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field, Inherited = false)]
    public sealed class ModelBackingPropertyAttribute : Attribute
    {
        #region State

        private readonly Type _valueType;
        private readonly String _propertyName;
        private readonly Boolean _isCollectionProperty;
        private readonly Nullable<ModelPropertyBehaviors> _behaviors;
        private readonly Boolean _isWrapped;

        #endregion

        #region Constructors

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="valueType">Type of value contained by this property</param>
        /// <param name="propertyName">Name of the propery which wraps this backing field</param>
        /// <param name="behaviors">Property behaviors</param>
        /// <param name="isCollectionProperty">True if this is a collection property, otherwise false</param>
        public ModelBackingPropertyAttribute(Type valueType, String propertyName, ModelPropertyBehaviors behaviors, Boolean isCollectionProperty)
            : this(valueType, propertyName, behaviors, isCollectionProperty, false)
        {
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="valueType">Type of value contained by this property</param>
        /// <param name="propertyName">Name of the propery which wraps this backing field</param>
        /// <param name="behaviors">Property behaviors</param>
        /// <param name="isCollectionProperty">True if this is a collection property, otherwise false</param>
        /// <param name="isWrapped">True to treat this as a wrapped property, otherwise false. If you're unsure, use false.</param>
        public ModelBackingPropertyAttribute
        (
            Type valueType,
            String propertyName,
            ModelPropertyBehaviors behaviors,
            Boolean isCollectionProperty,
            Boolean isWrapped
        ) : this(valueType, propertyName, (Nullable<ModelPropertyBehaviors>)behaviors, isCollectionProperty, isWrapped)
        {
        }

        /// <summary>
        /// Constructor to use if you do not want your property to have any behaviors
        /// </summary>
        /// <param name="valueType">Type of value contained by this property</param>
        /// <param name="propertyName">Name of the propery which wraps this backing field</param>
        /// <param name="isCollectionProperty">True if this is a collection property, otherwise false</param>
        /// <param name="isWrapped">True to treat this as a wrapped property, otherwise false. If you're unsure, use false.</param>
        public ModelBackingPropertyAttribute
        (
            Type valueType,
            String propertyName,
            Boolean isCollectionProperty,
            Boolean isWrapped
        ) : this(valueType, propertyName, null, isCollectionProperty, isWrapped)
        {
        }

        private ModelBackingPropertyAttribute
        (
            Type valueType,
            String propertyName,
            Nullable<ModelPropertyBehaviors> behaviors,
            Boolean isCollectionProperty,
            Boolean isWrapped
        )
        {
            if (valueType == null)
            {
                throw new ArgumentNullException("valueType");
            }

            if (String.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentNullException("propertyName");
            }

            _valueType = valueType;
            _propertyName = propertyName;
            _behaviors = behaviors;
            _isCollectionProperty = isCollectionProperty;
            _isWrapped = isWrapped;
        }

        #endregion

        #region Public

        /// <summary>
        /// Gets the type of value contained by this property
        /// </summary>
        public Type ValueType
        {
            get
            {
                return _valueType;
            }
        }

        /// <summary>
        /// Gets the name of the property that wraps this backing field
        /// </summary>
        public String PropertyName
        {
            get
            {
                return _propertyName;
            }
        }

        /// <summary>
        /// Gets the behaviors for this model property
        /// </summary>
        public Nullable<ModelPropertyBehaviors> Behaviors
        {
            get
            {
                return _behaviors;
            }
        }

        /// <summary>
        /// Gets whether or not this is a collection property
        /// </summary>
        public Boolean IsCollectionProperty
        {
            get
            {
                return _isCollectionProperty;
            }
        }

        /// <summary>
        /// Gets whether or not this property is wrapped
        /// </summary>
        public Boolean IsWrapped
        {
            get
            {
                return _isWrapped;
            }
        }

        #endregion
    }
}
